/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package grex.fitnessfunctions.Classification;

import grex.GP;
import grex.Options;
import grex.Prediction;
import grex.fitnessfunctions.IFitnessFunction;
import grex.PredictionContainer;
import grex.fitnessfunctions.FitnessFunction;
import grex.genes.*;

import java.io.Serializable;

/**
 *
 * @author RIK
 */
public class BrevityFitness extends FitnessFunction implements IFitnessFunction, Serializable {
    
    public BrevityFitness(){
        super(FitnessFunction.BRE);
    }
       
    @Override
    public double calcPredictionError(Prediction prediction, double targetValue) {
       return prediction.getPrediction() == targetValue ? 0 : 1;
    }
    
    @Override
    protected double calcParismonyPressure(GP gp){
        double pressure=0;        
        if(gp.getNrOfNodes()>options.getMAX_TREE_SIZE())
            pressure = gp.getNrOfNodes();
        pressure += calcBrevity(gp.getHead(),0)*options.getPUNISHMENT_FOR_LENGTH();
        return pressure;
    }
    

    @Override
    protected double calcFinalError(PredictionContainer pc){
        if(gp==null)
            return -999;
        return calcBrevity(gp.getHead(), 0)/getNrOfInstances();
    }
    
    @Override
    public double calcFitness(GP gp) throws GeneException{
        gp.train();
        this.gp=gp;
        options = gp.getOptions();
        this.pc=gp.getPcTrain();
         //This method is overridden since brevity does not measure accuracy. Hence the reported error is the brevity but accuracy still needs to be a part of the fitness function since brevity disregards predicitve performance.
        return normalizeTotalError(calcTotalError(pc)) + calcParismonyPressure(gp) * options.getPUNISHMENT_FOR_LENGTH();
    }
    
    private double calcBrevity(Gene gene,int depth){
        double brevity=0;
        Gene[] children = gene.getChildren();
        if(children != null){
            int i = 0;
            if(gene instanceof If)
                i++;
            for (; i < children.length; i++) {
                brevity+=calcBrevity(children[i],depth +1);
            }
        }else{
            brevity = ((ITerminal)gene).getCount()*depth;
            if(gene instanceof WRFPred)
                brevity = ((ITerminal)gene).getCount()*3;
        }        
        return brevity;        
    }
    
    /* public double calcFitness(GP gp) throws GeneException {
        Options options = gp.getOptions();
        gp.train();

        double trainFitness = 0, valFitness = 0;
        for (Prediction p : gp.getPcTrain().values()) {    
            if (p.getPrediction() != p.getTargetValue())
                trainFitness += 1;
        }
        double brevity = be.calcError(gp, "TRAIN")*options.getPUNISHMENT_FOR_LENGTH();
       // System.out.println("d" + d);
        trainFitness = (trainFitness / gp.getPcTrain().values().size()) * 100+ brevity;
        if(gp.getLength()>options.getMAX_TREE_SIZE())
            trainFitness +=gp.getLength();
        return trainFitness;
    }//*/
}
